﻿/*********************************************************************************
 *Author:         OnClick
 *Version:        1.0
 *UnityVersion:   2018.3.11f1
 *Date:           2019-04-07
 *Description:    IFramework
 *History:        2018.11--
*********************************************************************************/
using System;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

namespace IFramework
{
    public class ResourceManger : Singleton<ResourceManger>, IResourceManager
    {
        private ResAssetPool pool;
        private List<ResAsset> usePool;

        public override void OnSingletonInit()
        {
            if (!ABAssets.Instance.Init())
                Log.E("Assets.Initialize falied.");
            pool = new ResAssetPool();
            usePool = new List<ResAsset>();
        }
        public override void Dispose()
        {
            usePool.Clear();
            usePool = null;
            pool.Dispose();
            base.Dispose();
        }
        public UnityEngine.Object Load(string path, Type type, ResourceType resType)
        {
            for (int i = 0; i < usePool.Count; i++)
            {
                if (usePool[i].Path == path && usePool[i].Type == type)
                {
                    return usePool[i].Asset;
                }
            }
            ResAsset ResAsset = pool.Get();
            switch (resType)
            {
                case ResourceType.AssetBundle:
                    ABAsset abAsset = ABAssets.Instance.Load(path, type);
                    ResAsset.SetVal(abAsset, abAsset.Asset, resType, path, type);
                    break;
                case ResourceType.Resource:
                    UnityEngine.Object asset = Resources.Load(path, type);
                    ResAsset.SetVal(null, asset, resType, path, type);
                    break;
#if UNITY_EDITOR
                case ResourceType.Editor:
                    UnityEngine.Object editorAsset = AssetDatabase.LoadAssetAtPath(path, type);
                    ResAsset.SetVal(null, editorAsset, resType, path, type);
                    break;
#endif
                default:
                    return null;
            }
            usePool.Add(ResAsset);
            return ResAsset.Asset;
        }
        public T Load<T>(string path, ResourceType resType) where T : UnityEngine.Object
        {
            for (int i = 0; i < usePool.Count; i++)
            {
                if (usePool[i].Path == path && usePool[i].Type == typeof(T))
                {
                    return usePool[i].Asset as T;
                }
            }
            ResAsset ResAsset = pool.Get();
            switch (resType)
            {
                case ResourceType.AssetBundle:
                    ABAsset abAsset = ABAssets.Instance.Load<T>(path);
                    ResAsset.SetVal(abAsset, abAsset.Asset, resType, path, typeof(T));
                    break;
                case ResourceType.Resource:
                    UnityEngine.Object asset = Resources.Load<T>(path);
                    ResAsset.SetVal(null, asset, resType, path, typeof(T));
                    break;
#if UNITY_EDITOR
                case ResourceType.Editor:
                    UnityEngine.Object editorAsset = AssetDatabase.LoadAssetAtPath<T>(path);
                    ResAsset.SetVal(null, editorAsset, resType, path, typeof(T));
                    break;
#endif
                default:
                    return null;
            }
            usePool.Add(ResAsset);
            return ResAsset.Asset as T;
        }
        public UnityEngine.Object LoadAsync(string path, Type type, ResourceType resType)
        {

            for (int i = 0; i < usePool.Count; i++)
            {
                if (usePool[i].Path == path && usePool[i].Type == type)
                {
                    return usePool[i].Asset;
                }
            }
            ResAsset ResAsset = pool.Get();
            switch (resType)
            {
                case ResourceType.AssetBundle:
                    ABAsset abAsset = ABAssets.Instance.LoadAsync(path, type);
                    ResAsset.SetVal(abAsset, abAsset.Asset, resType, path, type);
                    break;
                case ResourceType.Resource:
                    UnityEngine.Object asset = Resources.LoadAsync(path, type).asset;
                    ResAsset.SetVal(null, asset, resType, path, type);
                    break;
#if UNITY_EDITOR
                case ResourceType.Editor:
                    Log.W("Do Not Use Async Load In Editor");
                    return null;
#endif
                default:
                    return null;
            }
            usePool.Add(ResAsset);
            return ResAsset.Asset;
        }
        public T LoadAsync<T>(string path, ResourceType resType) where T : UnityEngine.Object
        {
            for (int i = 0; i < usePool.Count; i++)
            {
                if (usePool[i].Path == path && usePool[i].Type == typeof(T))
                {
                    return usePool[i].Asset as T;
                }
            }
            ResAsset ResAsset = pool.Get();
            switch (resType)
            {
                case ResourceType.AssetBundle:
                    ABAsset abAsset = ABAssets.Instance.LoadAsync<T>(path);
                    ResAsset.SetVal(abAsset, abAsset.Asset, resType, path, typeof(T));
                    break;
                case ResourceType.Resource:
                    UnityEngine.Object asset = Resources.LoadAsync<T>(path).asset;
                    ResAsset.SetVal(null, asset, resType, path, typeof(T));
                    break;
#if UNITY_EDITOR
                case ResourceType.Editor:
                    Log.W("Do Not Use Async Load In Editor");
                    return null;
#endif
                default:
                    return null;
            }
            usePool.Add(ResAsset);
            return ResAsset.Asset as T;
        }
        public bool Unload(UnityEngine.Object asset, ResourceType resType)
        {
            for (int i = usePool.Count - 1; i >= 0; i--)
            {
                if (usePool[i].Asset == asset && usePool[i].ResType == resType)
                {
                    usePool.Remove(usePool[i]);
                    pool.Set(usePool[i]);
                    switch (resType)
                    {
                        case ResourceType.AssetBundle:
                            ABAssets.Instance.Unload(usePool[i].ABAsset);
                            break;
                        case ResourceType.Resource:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        case ResourceType.Editor:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            }
            return false;

        }
        public bool Unload(UnityEngine.Object asset)
        {
            for (int i = usePool.Count - 1; i >= 0; i--)
            {
                if (usePool[i].Asset == asset)
                {
                    usePool.Remove(usePool[i]);
                    pool.Set(usePool[i]);
                    switch (usePool[i].ResType)
                    {
                        case ResourceType.AssetBundle:
                            ABAssets.Instance.Unload(usePool[i].ABAsset);
                            break;
                        case ResourceType.Resource:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        case ResourceType.Editor:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            }
            return false;

        }
        public bool Unload(string path)
        {
            for (int i = usePool.Count - 1; i >= 0; i--)
            {
                if (usePool[i].Path == path)
                {
                    usePool.Remove(usePool[i]);
                    pool.Set(usePool[i]);
                    switch (usePool[i].ResType)
                    {
                        case ResourceType.AssetBundle:
                            ABAssets.Instance.Unload(usePool[i].ABAsset);
                            break;
                        case ResourceType.Resource:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        case ResourceType.Editor:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        default:
                            break;
                    }

                    return true;
                }
            }
            return false;

        }
        public bool Unload(string path, Type type)
        {
            for (int i = usePool.Count - 1; i >= 0; i--)
            {
                if (usePool[i].Path == path && usePool[i].Type == type)
                {
                    usePool.Remove(usePool[i]);
                    pool.Set(usePool[i]);
                    switch (usePool[i].ResType)
                    {
                        case ResourceType.AssetBundle:
                            ABAssets.Instance.Unload(usePool[i].ABAsset);
                            break;
                        case ResourceType.Resource:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        case ResourceType.Editor:
                            Resources.UnloadAsset(usePool[i].Asset);
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            }
            return false;
        }
        public bool UnLoad<T>(string path) where T : UnityEngine.Object
        {
            return Unload(path, typeof(T));
        }

    }

}
